#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdlib>
#include<random>

using std::string;
using std::cout;
using std::endl;

class CubeSide {
public:
    virtual const char* getName() = 0;
    virtual void Fidget() = 0;
};

class FidgetCube {
public:
    CubeSide* getSide(uint8_t sideNo) const
    {
        return sides[sideNo];
    }
    bool addSide(CubeSide* newSide)
    {
        if (lastSide < 6) {
            sides[lastSide] = newSide;
            lastSide++;
            return true;
        }
        return false;
    }
protected:
    CubeSide* sides[6];
    uint8_t lastSide = 0;
};


class DialSide : public CubeSide {
public:
    const char* getName()
    {
        return DialSide::dialSideName;
    }
    void setDial(uint16_t value)
    {
        if (dialValue <= 10) {
            dialValue = value;
            cout << "A dial was set to " << dialValue << "." << endl;
        }
    }

    void Fidget() override{
        dialValue = rand() % 11; 
        cout << "Dial set to " << dialValue << "." << endl;
    }
protected:
    uint16_t dialValue = 0;
    static constexpr char const* dialSideName = "Dial";
};


class DialCube : public FidgetCube {
public:
    DialCube() : FidgetCube() {
        for (uint8_t x = 0; x < 6; x++) {
            addSide(new DialSide());
        }
    }
};



class JoystickSide : public CubeSide {
public:
    const char* getName() override { return "Joystick"; }
    void push(const char* direction) 
    {
        cout << "Joystick pushed " << direction << endl;
    }

    void Fidget() override{
        const char* directions[] = { "up", "down", "left", "right" };
        int randomDirection = rand() % 4; 
        cout << "Joystick pushed " << directions[randomDirection]  << endl;
    }
};



class JoystickDialCube : public FidgetCube {
public:
    JoystickDialCube(uint8_t numJoysticks, uint8_t numDials) {
        uint8_t addedSides = 0;

        for (uint8_t i = 0; i < numJoysticks && addedSides < 6; i++) {
            addSide(new JoystickSide());
            addedSides++;
        }

        for (uint8_t i = 0; i < numDials && addedSides < 6; i++) {
            addSide(new DialSide());
            addedSides++;
        }
    }
};


void playWith(FidgetCube& cube) {
    for (uint8_t i = 0; i < 6; ++i) {
        CubeSide* side = cube.getSide(i);
        if (side) {
            cout << side->getName();
            side->Fidget();
        }
    }
}

class RandomCube : public FidgetCube {
public:
    RandomCube() {
        for (uint8_t i = 0; i < 6; i++) {
            if (rand() % 2 == 0) {
                addSide(new JoystickSide());
            }
            else {
                addSide(new DialSide());
            }
        }
    }
};



class ButtonSide : public CubeSide {
public:
    ButtonSide() : displayValue(5) {} // Initialize displayValue to 5
    const char* getName() override { return "Button"; }
    void Fidget() override;
    void pressButton1();
    void pressButton2();
protected:
    int displayValue;
};

void ButtonSide::pressButton1() {
    if (displayValue < 9) {
        displayValue++;
    }
    cout << "Display: " << displayValue << endl;
}

void ButtonSide::pressButton2() {
    if (displayValue > 0) {
        displayValue--;
    }
    cout << "Display: " << displayValue << endl;
}

void ButtonSide::Fidget() {
    if (rand() % 2 == 0) {
        cout << "Button 1 pressed. ";
        pressButton1();
    }
    else {
        cout << "Button 2 pressed. ";
        pressButton2();
    }
}

int main() {
   /* DialCube theDialCube;
    cout << theDialCube.getSide(0)->getName() << endl;
    ((DialSide*)theDialCube.getSide(0))->setDial(5);*/

   /* cout << "question 3" << endl;
    FidgetCube myCube;

    for (int i = 0; i < 3; ++i) {
        myCube.addSide(new JoystickSide());
    }

    JoystickSide* joystick;
    joystick = static_cast<JoystickSide*>(myCube.getSide(0));
    joystick->push("up");

    joystick = static_cast<JoystickSide*>(myCube.getSide(1));
    joystick->push("down");

    joystick = static_cast<JoystickSide*>(myCube.getSide(2));
    joystick->push("left");*/


 /*   cout << endl;
    cout << "question 4" << endl;
    JoystickDialCube cube1(2, 3);
    for (uint8_t i = 0; i < 6; ++i) {
        CubeSide* side = cube1.getSide(i);
        if (side) cout << "Side " << (int)i << ": " << side->getName() << endl;
    }*/


    //cout << endl;
    //cout << "question 5" << endl;
    srand(time(0)); 

    //JoystickDialCube myCube2(3, 2);

    //cout << "Testing Fidget interactions:" << endl;
    //for (uint8_t i = 0; i < 6; ++i) {
    //    CubeSide* side = myCube2.getSide(i);
    //    if (side) {
    //        cout << side->getName() << " side interaction: ";
    //        side->Fidget();
    //    }
    //}

    /*cout << endl;
    cout << "question 6" << endl;
    JoystickDialCube myCube(3, 2);
    cout << "Playing with the FidgetCube:" << endl;
    playWith(myCube);*/



    /*cout << endl;
    cout << "question 7" << endl;
    RandomCube myRandomCube;
    playWith(myRandomCube);*/


    cout << endl;
    cout << "question 8" << endl;
    ButtonSide myButtonSide;
    cout << "Testing ButtonSide:" << endl;

    cout << "Initial Display: " << 5 << endl; // Starting at default value 5
    myButtonSide.pressButton1(); // 6
    myButtonSide.pressButton1(); // 7
    myButtonSide.pressButton1(); // 8
    myButtonSide.pressButton1(); // 9
    myButtonSide.pressButton1(); 
    myButtonSide.pressButton2(); 
    myButtonSide.pressButton2(); 
    myButtonSide.pressButton2(); 
    myButtonSide.pressButton2(); 
    myButtonSide.pressButton2(); 
 



    return 0;
}
